import unittest
from appium import webdriver
from appium.options.common import AppiumOptions
from utils.logger import get_logger, set_driver_instance
import yaml
import os
from datetime import datetime


class BaseTest(unittest.TestCase):
    # 类变量，用于存储driver实例
    driver = None

    @classmethod
    def setUpClass(cls):
        """
        测试类初始化方法，在所有测试方法执行前调用一次
        负责初始化Appium驱动和加载配置
        """
        cls.logger = get_logger()

        try:
            # 获取项目根目录的绝对路径
            project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            config_path = os.path.join(project_root, "data", "config.yaml")
            
            # 明确指定使用 utf-8 编码读取配置文件
            with open(config_path, "r", encoding="utf-8") as f:
                config = yaml.safe_load(f)

            # 兼容两种配置格式
            # 新格式
            if 'capabilities' in config:
                capabilities = config.get('capabilities', {})
                server_url = config.get('appium', {}).get('server', 'http://localhost:4723/wd/hub')
            # 旧格式
            else:
                capabilities = config.get('appium', {})
                server_config = config.get('server', {})
                server_url = server_config.get('url', 'http://localhost:4723/wd/hub')

            # 验证配置是否完整
            if not capabilities or not isinstance(capabilities, dict):
                raise ValueError("Appium 配置不完整或格式错误，请检查 config.yaml")

            cls.logger.info("配置文件加载成功。")
            cls.logger.debug(f"Capabilities 配置: {capabilities}")
            cls.logger.debug(f"Server URL: {server_url}")

            # 创建Appium选项对象并设置相关参数
            appium_options = AppiumOptions()
            # 处理带前缀的 capability 名称
            for key, value in capabilities.items():
                # 移除 "appium:" 前缀，如果有的话
                clean_key = key.replace("appium:", "") if key.startswith("appium:") else key
                appium_options.set_capability(clean_key, value)

            cls.logger.debug(f"appium_options 类型: {type(appium_options)}")

            # 初始化WebDriver
            cls.driver = webdriver.Remote(server_url, options=appium_options)
            # 设置driver实例供日志截图使用
            set_driver_instance(cls.driver)
            cls.logger.info("Appium driver initialized.")

        except FileNotFoundError as e:
            cls.logger.error(f"配置文件未找到: {e}")
            raise
        except yaml.YAMLError as e:
            cls.logger.error(f"解析 YAML 配置文件时出错: {e}")
            raise
        except ValueError as e:
            cls.logger.error(f"配置文件验证失败: {e}")
            raise
        except Exception as e:
            cls.logger.error(f"初始化 WebDriver 时发生错误: {e}")
            raise

    @classmethod
    def tearDownClass(cls):
        """
        测试类清理方法，在所有测试方法执行后调用一次
        负责关闭Appium驱动
        """
        try:
            if cls.driver:
                cls.driver.quit()
                cls.logger.info("Appium driver closed.")
        except Exception as e:
            cls.logger.error(f"关闭 Appium driver 时发生错误: {e}")

    def capture_screenshot_on_failure(self):
        """在失败的测试用例中截图并记录日志"""
        case_name = self._testMethodName
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        # 获取项目根目录的绝对路径
        project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        screenshot_dir = os.path.join(project_root, "reports", "screenshots")
        os.makedirs(screenshot_dir, exist_ok=True)
        screenshot_path = os.path.join(screenshot_dir, f"{case_name}_{timestamp}.png")
        try:
            self.driver.save_screenshot(screenshot_path)
            self.logger.info(f"截图保存到: {screenshot_path}")
            return screenshot_path
        except Exception as e:
            self.logger.error(f"截图保存失败: {e}")
            return None

    def tearDown(self):
        """在失败的测试用例中截图并记录日志"""
        # 兼容不同版本的unittest，处理_outcome属性差异
        has_failed = False
        
        if hasattr(self, '_outcome'):
            # 新版本unittest
            if hasattr(self._outcome, 'errors'):
                result = self._outcome.errors
                has_failed = any(result)
            elif hasattr(self._outcome, '_excinfo'):
                result = self._outcome._excinfo
                has_failed = result is not None
            else:
                result = None
        else:
            result = None
            
        # 如果测试失败，则截图
        if has_failed:
            self.capture_screenshot_on_failure()

    def log_error_and_capture_screenshot(self, message):
        """记录错误日志并截图"""
        self.logger.error(message)
        return self.capture_screenshot_on_failure()